
import type { InjectionKey, ShallowRef, UnwrapRef } from 'vue'
import {
  provide,
  inject,
  reactive,
  ref,
  shallowRef,
  readonly,
  watch
} from 'vue'

// 引入接口
import type {
  IGridSelection, // 列表里面选择的记录
  TListState, // 列表的状态
  TQueryState, // 查询状态
  TPagerState, // 分页状态
  TCompany,
  TResource // 返回记录的类型
} from '../type'
 
// 用 Symbol 做标记，避免重名冲突
const flag = Symbol('pager') as InjectionKey<string>

/**
 * 创建数据列表的状态，局部有效
 * @param service 获取数据的回调函数。
 * * service: (
 * * * query: TQueryState,
 * * *  pagerInfo: TPagerState
 * * ) => Promise<TResource<T>>
 * @returns 总记录数和列表数据， Promise<TResource<T>>
 */
export function createListState<T extends object>(
    service: (
      query: TQueryState,
      pagerInfo: TPagerState
    ) => Promise<TResource<T>>
  ) {
  
    // 记录列表数据
    const dataList = shallowRef<Array<T>>([])

    // 查询状态
    const query: TQueryState = reactive({
      mini: {}, // 查询条件的精简形式
      array: [], // 查询条件的对象形式
    })

    // 分页状态
    const pagerState: TPagerState = reactive({
      pagerSize: 5,
      count: 20, // 总数
      pagerIndex: 1 // 当前页号
    })

    // 选择的记录
    const selection: IGridSelection<T> = reactive({
      dataId: '',
      row: {} ,
      dataIds: [] as number[],
      rows: []  
    })
 
    // 弹窗状态，添加修改后更新
    const crudState = reactive({
      addCount: 0,
      updateCount: 0,
      deleteCount: 0,
      dialog: {
        addShow: false,
        updateShow: false,
        subShow: false
      }
    })
    /**
     * 内部用的更新数据的函数，
    */
    async function updateData () {
      // 获取数据
      const { allCount, list } = await service(query, pagerState)
      // 设置
      pagerState.count = allCount
      dataList.value = list
    }

    // 是否需要加载数据
    let canUpdate = true
    // 监听查询条件，更新数据
    watch(query.mini, async () => {
      // 设置为不需要 翻页触发
      canUpdate = false
      // 设置到第一页
      pagerState.pagerIndex = 1
      await updateData()
      canUpdate = true
    })

    // 监听页号，翻页后更新数据
    watch(() => pagerState.pagerIndex, () => {
      if (canUpdate) {
        updateData()
      }
    }, {
      immediate: true // 立即执行
    })

    // 添加后更新
    watch(() => crudState.addCount, async () => {
      // 设置为不需要 翻页触发
      canUpdate = false
      // 设置到第一页
      pagerState.pagerIndex = 1
      await updateData()
      canUpdate = true
    })

    // 修改后更新
    watch(() => crudState.updateCount, async () => {
      // 在当前页更新
      // 不需要重新统计总记录数
      await updateData()
      canUpdate = true
    })

    // 删除后更新
    watch(() => crudState.deleteCount, async () => {
      // 在当前页更新
      // 需要重新统计总记录数
      await updateData()
      canUpdate = true
    })

    // 整合需要暴露出去的数据和方法
    // 如果需要只读，可以使用 readonly 
    const state: TListState<T> = {
      // updateData, // 其实是内部使用的。
      // 列表数据的容器
      dataList,
      // 列表里面选择的记录
      selection,
      // 弹窗状态，添加修改的状态
      crudState,
      // 翻页的状态
      pagerState,
      // 查询条件
      query 
    }

    // 依赖注入，共享给子组件 
    provide<TListState<T>>(flag, state)

    // 返回给父组件
    return state
  }

/**
 * 子组件用 inject 获取状态
 * @returns TListState<T>
 */
export function getListState<T extends object>(): TListState<T> {
  const re = inject<TListState<T>>(flag) 
  return re as TListState<T>
}
 
